// ====================================================================
//  rx_extract.cxx extract delineated data stream to file
//
// Copyright W1HKJ, Dave Freese 2006
//
// fldigi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems to "w1hkj@w1hkj.com".
//
// ====================================================================

#include <config.h>

#include <iostream>
#include <fstream>
#include <string>
#include <signal.h>

#include "rx_extract.h"
#include "main.h"
#include "status.h"
#include "fl_digi.h"
#include "configuration.h"

#include "extra.h"
#include <algorithm>

using namespace std;

//const char *beg = "$$";
const char *end = "\n";
//const char *end = "*00"; //suggested end character, perhaps just * and then treat the number afterwards as a checksum?
const char *txtWrapInfo = "\
Detect the occurance of $$ and *00\n\
Function to search for telemetry strings in recived data\n\
Uploads detected strings to DL server which are then plotted onto\n\
http://spacenear.us/tracker\n"; 

#define   bufsize  16
char  rx_extract_buff[bufsize + 1];
string rx_buff;
string rx_extract_msg;
bool extracting = false;
bool bInit = false;

char dttm[64];

//Default rules
int total_string_length = 100;
int min_number_fields = 8;
int field_length = 10;

int dodge_data = 0;
bool validate_output;
int number_commas;
int old_i = 0, field_number = 0;
string rx_buff_edit;
string tmpfield;

string plussign ("+");
size_t found;


void TrimSpaces( string& str)  
{  
	
	// Trim Both leading and trailing spaces  
	size_t startpos = str.find_first_not_of(" "); // Find the first character position after excluding leading blank spaces  
	size_t endpos = str.find_last_not_of("\r\n");  // Find the first character position from reverse af  

	// if all spaces or empty return an empty string  
	if(( string::npos == startpos ) || ( string::npos == endpos))  
	{  
		str = "";  
	}  
	else  
		str = str.substr( startpos, endpos-startpos+1 );  
} 

void UpperCase(string& str)
{
	for(int i = 0; i < str.length(); i++)
	{
		str[i] = toupper(str[i]);
	}
	return;
}

void rx_extract_reset()
{
	rx_buff.clear();
	memset(rx_extract_buff, ' ', bufsize);
	rx_extract_buff[bufsize] = 0;
	extracting = false;
}

void rx_extract_add(int c)
{

	extern int rjh_pfds[2];

	if (!c) return;
	
	if (!bInit) {
		rx_extract_reset();
		bInit = true;
	}	
	char ch = (char)c;

	memmove(rx_extract_buff, &rx_extract_buff[1], bufsize - 1);
	rx_extract_buff[bufsize - 1] = ch;
	//Reads the stentence delimter previously read from the xml file.
	const char* string_s_delimiter = (progdefaults.xmlSentence_delimiter.empty() ? "UNKNOWN" : progdefaults.xmlSentence_delimiter.c_str());
	if ( strstr(rx_extract_buff, string_s_delimiter) != NULL ) {
		rx_buff = rx_extract_buff;
		rx_extract_msg = "Extracting";
		
		put_status(rx_extract_msg.c_str(), 60, STATUS_CLEAR);
		
		memset(rx_extract_buff, ' ', bufsize);
		extracting = true;
	} else if (extracting) {
		rx_buff += ch;
		if (strstr(rx_extract_buff, end) != NULL) {
			struct tm tim;
			time_t t;
			time(&t);
	        gmtime_r(&t, &tim);
			strftime(dttm, sizeof(dttm), "%Y%m%d-%H%M", &tim);
			
			string outfilename = WrapDir;
			outfilename.append("data");
			outfilename.append(dttm);
			outfilename.append(".wrap");			
			ofstream extractstream(outfilename.c_str(), ios::binary);
			if (extractstream) {
				extractstream << rx_buff;
				extractstream.close();
			}
			rx_extract_msg = "File saved in temp folder";
			put_status(rx_extract_msg.c_str(), 20, STATUS_CLEAR);
			
			//Trim Spaces
			TrimSpaces(rx_buff);
			
			// Find the sentence start marker and remove up to the end of it
			// dkjhdskdkfdakhd $$icarus,...   -> icarus,...

			rx_buff = rx_buff.substr(
				rx_buff.find(progdefaults.xmlSentence_delimiter)+
				progdefaults.xmlSentence_delimiter.length());
			
			// replace the tx callsign with our selected callsign
			if (progdefaults.replacetxcallsign == 1) {
#if !defined(__CYGWIN__)
				cout << "Replacing callsign" << endl;
#endif
				rx_buff = rx_buff.substr(rx_buff.find(progdefaults.xmlField_delimiter));
				rx_buff.insert(0, progdefaults.xmlCallsign);
			}

			//Counts number of fields
			number_commas = count(rx_buff.begin(), rx_buff.end(), progdefaults.xmlField_delimiter.at(0));
			
			//Gets info for number of fields
			min_number_fields = atoi(progdefaults.xmlFields.c_str());
			
			//Check rules - telem string length and number of fields and whether each field has been validated
			if ((rx_buff.length() < total_string_length) and (number_commas == min_number_fields - 1)) {
					string identity_callsign = (progdefaults.myCall.empty() ? "UNKNOWN" : progdefaults.myCall.c_str());
					UpperCase (identity_callsign);

					string string_payload = (progdefaults.flight_sel.empty() ? "UNKNOWN" : progdefaults.flight_sel.c_str());
					UpperCase (string_payload);
					
					
					//Find the + sign and swap it to something that will get posted -jcoxon 24/2/10
					found=rx_buff.find(plussign);
					while (found!=string::npos) {
						rx_buff.replace(rx_buff.find(plussign),plussign.length(),"%2B");
						found=rx_buff.find(plussign, found+1);
					}
					
					string postData = "string=" + rx_buff + "&identity=" + identity_callsign + "&xml="+ string_payload + "\n";
					
					//We really don't want people sending status updates from UNKNOWN - somehow need to remind people to change their callsign
					if (identity_callsign != "UNKNOWN") { 
#if !defined(__CYGWIN__)
						cout << "PARENT: sent " + postData ;
#endif
						const char* data = postData.c_str();
						write (rjh_pfds[1],data,strlen(data));
						rx_extract_msg = "Data uploaded to server";
						put_status(rx_extract_msg.c_str(), 20, STATUS_CLEAR);
					}
					else {
#if !defined(__CYGWIN__)
						cout << "Need to enter a callsign, please go to 'Configure' then 'Operator' and add a callsign/nickname.\n";
#endif
					}
			}
			rx_extract_reset();
		} else if (rx_buff.length() > 16384) {
			rx_extract_msg = "Extract length exceeded 16384 bytes";
			put_status(rx_extract_msg.c_str(), 20, STATUS_CLEAR);
			rx_extract_reset();
		}
	}
}
